#----------------------------------------------------------------------------
# wxPita - wxPython wrapper library for painless layout and event binding
#
# Author:       Feihong Hsu
# Email:        hsu DOT feihong AT yahoo DOT com
# Website:      http://wxpita.googlecode.com/
# Created:      2007 Dec 15
# Copyright:    (c) 2007 by Feihong Hsu
# License:      BSD License
#----------------------------------------------------------------------------
import re
import xml.etree.cElementTree as et
import wrappers

def fromxml(markup, dictionary=wrappers.__dict__):
    if isinstance(markup, basestring):
        root = et.fromstring(markup)
    else:
        # File-like object:
        root = et.parse(xml).getroot()

    def get_wrapper(node):
        wrapper_cls = dictionary.get(node.tag)
        args = {}
        for k, v in node.attrib.items():
            if v.startswith('{') and v.endswith('}'):
                v = eval(v[1:-1])
            args[k] = v

        wrapper = wrapper_cls(**args)

        children = [get_wrapper(n) for n in node.getchildren()]
        if children:
            wrapper = wrapper[children]
        
        return wrapper

    return get_wrapper(root)

def fromstring(markup, dictionary=wrappers.__dict__):
    "Convert PitaML markup to a wrapper object"
    root = getroot(markup)
    
    def get_wrapper(node):
        wrapper_cls = dictionary.get(node.name)
        args = {}
        for k, v in node.attrs.items():
            if v.startswith('{') and v.endswith('}'):
                v = eval(v[1:-1])
            args[k] = v
            
        wrapper = wrapper_cls(**args)
        children = [get_wrapper(n) for n in node.children]
        if children:
            wrapper = wrapper[children]
            
        return wrapper

    return get_wrapper(root)

def fromfile(filename, dictionary=wrappers.__dict__):
    return fromstring(open(filename).read())

def getroot(markup):
    levels = {}         # maps indent count to level
    nodes = [[]]        # dictionary of lists
    attr_pattern = re.compile(r'^\w+\s*=')
    
    for line in markup.split('\n'):
        if line.strip():
            indent = indentcount(line)
            if not indent in levels:
                levels[indent] = len(levels)
            level = levels[indent]

            text = line.strip()

            if attr_pattern.match(text):
                for k, v in getattrs(text):
                    nodes[level-1][-1].attrs[k] = v
            else:
                if level >= len(nodes):
                    nodes.append([])

                node = getnode(text)
                nodes[level].append(node)
                if level != 0:
                    nodes[level-1][-1].addchild(node)

    return nodes[0][0]

def indentcount(text):
    for i in range(len(text)):
        if text[i] != ' ':
            return i
    return None

def getnode(text):
    parts = re.split('\s+', text, 1)
    name, attrstr = parts if len(parts) == 2 else (text.strip(), None)
    node = Node(name)
    for k, v in getattrs(attrstr):
        node.attrs[k] = v
    return node

def getattrs(text):
    if text:
        for part in text.split(';'):
            k, v = part.split('=')
            yield k.strip(), v.strip()

class Node(object):
    def __init__(self, name):
        self.name = name
        self.attrs = {}
        self.children = []

    def addchild(self, child_node):
        self.children.append(child_node)
